package com.cskaoyan.service.back.configmanagement;


import com.cskaoyan.bean.po.MarketRegion;
import com.cskaoyan.bean.po.MarketSystem;
import com.cskaoyan.bean.po.MarketSystemExample;
import com.cskaoyan.bean.vo.back.configmanagement.FreightConfigVo;
import com.cskaoyan.bean.vo.back.configmanagement.MallConfigVo;
import com.cskaoyan.bean.vo.back.configmanagement.OrderConfigVo;
import com.cskaoyan.bean.vo.back.configmanagement.WXConfigVo;
import com.cskaoyan.exception.MarketValidationException;
import com.cskaoyan.mapper.MarketRegionMapper;
import com.cskaoyan.mapper.MarketSystemMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 配置管理服务impl
 *
 * @author 李然
 * @date 2022/10/12
 */
@Service
public class ConfigManageServiceImpl implements ConfigManageService {

    @Autowired
    MarketSystemMapper systemMapper;
    @Autowired
    MarketRegionMapper regionMapper;

    /**
     * 得到配置购物中心
     * 回显商场配置信息
     *
     * @return 商场配置详细信息
     */
    @SneakyThrows
    @Override
    public MallConfigVo getConfigMall() {
        Object object = setField(MallConfigVo.class);

        return (MallConfigVo) object;
    }

    /**
     * 得到配置运输
     * 配置管理模块中,回显运费配置模块的信息
     *
     * @return 返回运费配置信息
     */
    @SneakyThrows
    @Override
    public FreightConfigVo getConfigExpress() {
        Object object = setField(FreightConfigVo.class);

        return (FreightConfigVo) object;
    }

    /**
     * 得到配置订单
     * 配置管理模块中,回显订单配置模块的信息
     *
     * @return 返回订单配置信息
     */
    @Override
    public OrderConfigVo getConfigOrder() {
        Object object = setField(OrderConfigVo.class);
        return (OrderConfigVo) object;
    }

    /**
     * 得到配置微信
     * 配置管理模块中,回显小程序配置模块的信息
     *
     * @return 返回小程序配置信息
     */
    @Override
    public WXConfigVo getConfigWX() {
        Object object = setField(WXConfigVo.class);
        return (WXConfigVo) object;
    }

    /**
     * 配置模块中,修改商品配置信息
     *
     * @param mallConfigVo 前端传来的商场配置的详细信息
     * @return 返回修改的记录数
     */
    @Override
    public int postConfigMall(MallConfigVo mallConfigVo) {
        int count = updateData(mallConfigVo);
        return count;
    }

    /**
     * 配置模块中,修改运费配置信息
     *
     * @param freightConfigVo 前端传来的运费配置的详细信息
     * @return 返回修改的记录数
     */
    @Override
    public int postConfigExpress(FreightConfigVo freightConfigVo) {
        int count = updateData(freightConfigVo);
        return count;
    }

    /**
     * 配置模块中,修改订单配置信息
     *
     * @param orderConfigVo 前端传来的订单配置的详细信息
     * @return 返回修改的记录数
     */
    @Override
    public int postConfigOrder(OrderConfigVo orderConfigVo) {
        int count = updateData(orderConfigVo);
        return count;
    }

    /**
     * 配置模块中,修改小程序配置信息
     *
     * @param wxConfigVo 前端传来的小程序配置的详细信息
     * @return 返回修改的记录数
     */
    @Override
    public int postConfigWX(WXConfigVo wxConfigVo) {
        int count = updateData(wxConfigVo);
        return count;
    }

    /**
     * 反射获取配置模块从前端传来的数据,然后赋值给system
     *
     * 传入system 和匹配条件 (keyName=数据库中的key_name值),来修改数据库记录
     *
     * @param object 前端传来的数据封装的JSON对象
     * @return 修改记录的条数
     */
    @SneakyThrows
    public int updateData(Object object) {
        //拿取该对象的所有字段名
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();

        //统计修改的字段的记录
        int count = 0;
        for (Field field : fields) {

            count++;

            MarketSystem system = new MarketSystem();

            String keyName = field.getName();

            system.setKeyName(keyName);


            //数据库的匹配条件  keyName = field名
            MarketSystemExample systemExample = new MarketSystemExample();
            MarketSystemExample.Criteria criteria = systemExample.createCriteria();
            criteria.andKeyNameEqualTo(keyName);

            //将首字母转换为大写
            keyName = keyName.substring(0, 1).toUpperCase() + keyName.substring(1);

            //拿到get方法,获取该对象里字段的值

            Method method = clazz.getDeclaredMethod("get" + keyName);
            Object keyValue = method.invoke(object);

            //校验商场位置是否合法
            if ("Market_mall_address".equals(keyName)) {

                //查询表中的中国行政区
                List<MarketRegion> regions = regionMapper.selectByExample(null);

                ArrayList<String> regionList = new ArrayList<>();
                for (MarketRegion region : regions) {
                    regionList.add(region.getName());
                }

                String addr = (String) keyValue;
                String[] split = addr.split("-");


                for (String s : split) {
                    if (!regionList.contains(s)) {
                        throw new MarketValidationException("此商场位置结尾不是区域类型或不是中国行政区域");

                    }

                }


            }

            //赋值给system对象
            system.setKeyValue(keyValue.toString());
            system.setUpdateTime(new Date());


            //修改数据库信息
            systemMapper.updateByExampleSelective(system, systemExample);

        }
        return count;
    }


    /**
     * 根据传入的实体类的类对象,来给这个类的成员变量赋值,返回一个已经赋值的对象
     *
     * @param clazz 实体类对象
     * @return 已经赋值的对象
     */
    @SneakyThrows
    public Object setField(Class clazz) {
        //获取这个表的所有数据
        List<MarketSystem> marketSystem = systemMapper.selectByExample(null);

        //创建实例对象
        Constructor<?> constructor = clazz.getConstructor();
        Object object = constructor.newInstance();

        //获取这个对象的所有字段名
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            //字段名
            String name = field.getName();
            for (MarketSystem system : marketSystem) {

                //匹配到字段则进行赋值
                if (name.equals(system.getKeyName())) {
                    Field declaredField = clazz.getDeclaredField(name);
                    declaredField.setAccessible(true);
                    declaredField.set(object, system.getKeyValue());
                }

            }

        }
        return object;

    }


}

